//* visual representation of players

function Avatar(ARace,AHairstyle) {
  // constructor
  this.x = 100;
  this.y = 100;
  this.fx = 0;
  this.fy = 0;
  this.fringeHook = 0;
  this.action = 'stand';
  this.animation = 'down';
  this.sitTime = 0;
  this.odx = 0;
  this.ody = 0;
  this.initialized = false; // my own avatar is first time initialized from server asta, this is then set to true
  this.user = 0; // owner of the avatar, it is used to keep track of which asta is which avatar[]
  if ( (ARace!='male')&&(ARace!='female') )
		throw "Avatar: unsupported race '"+ARace+"'";
  this.race = ARace;
  this.body      = new MetaSprite(-100,'nobody'/*this.race*/);
	this.hairstyle = null; //new MetaSprite(-AHairstyle,'any');
	this.leg       = null; //new MetaSprite(586,this.race);
	this.chest     = null; //new MetaSprite(1202,this.race);
	this.feet      = null; //new MetaSprite(2155,this.race);
  this.hands     = null; //new MetaSprite(531,this.race);
  this.head      = null; //new MetaSprite(544,'any'); 
  this.chat = '';
  this.chat_time = 0;

  // movement
  this.movement = function(AKeyMap) {
    // update movements with keys
    // do nothing if map not loaded
    if (!map.layer[map.collision])
      return;
    if (!map.layer[map.collision].data)
      return;
    if (!map.layer[map.collision].data[0][0])
      return;
    // which keys
    var speed = 16;
    if (AKeyMap) {
      var moving = false;
      var moved_x = false;
      var moved_y = false;
      // 1 movement if previous wasn't finished to 32x grid
      //if ( !(AKeyMap[37] || AKeyMap[39] || AKeyMap[38] || AKeyMap[40]) ) {
      //  this.x += this.odx;
      //  this.y += this.ody;
      //}
      if ( !(AKeyMap[37] || AKeyMap[39]) ) {
        // FIXME: this still doesn't work
        if ((this.x+16) % 32 != 0) {
          this.x += this.odx;
          moved_x = true;
        }
      }
      if ( !(AKeyMap[38] || AKeyMap[40]) ) {
        // FIXME: this still doesn't work
        if (this.y % 32 != 0) {
          this.y += this.ody;
          moved_y = true;
        }
      }
//      this.odx = 0;
//      this.ody = 0;
      if (this.action != 'sit') {
        // calculate colisions
        var collision_now  = map.layer[map.collision].data[Math.floor(this.y / 32)+1][Math.floor(this.x / 32)+1] > 0;
        var collision_left = map.layer[map.collision].data[Math.floor((this.y - 0)/ 32)+1][Math.floor((this.x - 0) / 32)+1-1] > 0;
        var collision_right = map.layer[map.collision].data[Math.floor((this.y - 0)/ 32)+1][Math.floor((this.x - 16)/ 32)+1+1] > 0;
        var collision_up = map.layer[map.collision].data[Math.floor((this.y + 16)/ 32)+1-1][Math.floor(this.x / 32)+1] > 0;
        var collision_down = map.layer[map.collision].data[Math.floor(this.y / 32)+1+1][Math.floor(this.x / 32)+1] > 0;

        // detect corner collision (if both keys are pressed)
        // left + up
        if (AKeyMap[37]&&AKeyMap[38]) {
          var pom = map.layer[map.collision].data[Math.floor((this.y + 16)/ 32)+1-1][Math.floor((this.x - 0) / 32)+1-1] > 0;
          collision_left = pom||collision_left;
          collision_up = pom||collision_up;
        }
        // left + down
        if (AKeyMap[37]&&AKeyMap[40]) {
          var pom = map.layer[map.collision].data[Math.floor((this.y - 0)/ 32)+1+1][Math.floor((this.x - 0) / 32)+1-1] > 0;
          collision_left = pom||collision_left;
          collision_down = pom||collision_down;
        }
        // right + up
        if (AKeyMap[39]&&AKeyMap[38]) {
          var pom = map.layer[map.collision].data[Math.floor((this.y + 16)/ 32)+1-1][Math.floor((this.x - 16) / 32)+1+1] > 0;
          collision_right = pom||collision_right;
          collision_up = pom||collision_up;
        }
        // right + down
        if (AKeyMap[39]&&AKeyMap[40]) {
          var pom = map.layer[map.collision].data[Math.floor((this.y - 0)/ 32)+1+1][Math.floor((this.x - 16) / 32)+1+1] > 0;
          collision_right = pom||collision_right;
          collision_down = pom||collision_down;
        }

        // normal H/V collisions
        // left
        if (AKeyMap[37]) {
          moving = true;
          if (this.action != 'left') 
            this.update('walk','left');
          if (!collision_left) { 
            if (!moved_x)
              this.x -= speed;
            this.odx = -speed;
          }
        }
        // right
        if (AKeyMap[39])  {
          moving = true;
          if (this.action != 'right')
            this.update('walk','right');
          if (!collision_right) {
            if (!moved_x)
              this.x += speed;
            this.odx = +speed;
          }
        }
        // up
        if (AKeyMap[38]) {
          //debug('moving up - current: '+Math.floor(this.x / 32)+','+Math.floor(this.y / 32)+', next: '+Math.floor(this.x / 32)+','+(Math.floor(this.y / 32)-1));
          //var collision_now  = map.layer[map.collision].data[Math.floor(this.y / 32)+1][Math.floor(this.x / 32)+1] > 0;
          //var collision_next = map.layer[map.collision].data[Math.floor(this.y / 32)+1-1][Math.floor(this.x / 32)+1] > 0;
          //debug('  now='+collision_now+' next='+collision_next);
          moving = true;
          if (this.action != 'up')
            this.update('walk','up');
          if (!collision_up) {
            if (!moved_y)
              this.y -= speed;
            this.ody = -speed;
          }
        }
        // down
        if (AKeyMap[40]) {
          moving = true;
          if (this.action != 'down')
            this.update('walk','down');
          if (!collision_down) {
            if (!moved_y)
              this.y += speed;
            this.ody = +speed;
          }
        }
        // stop moving
        if ( (this.action=='walk')&&(!moving) )
          this.update('stand',this.animation);
      } else {
        // turning around while sit
        if (AKeyMap[37]) this.update(this.action,'left');
        if (AKeyMap[39]) this.update(this.action,'right');
        if (AKeyMap[38]) this.update(this.action,'up');
        if (AKeyMap[40]) this.update(this.action,'down');
      }
      // sit
      var t = new Date().getTime();
      if ( (AKeyMap[83])&&(t-this.sitTime > 500) ) {
        moving = false;
        this.sitTime = t;
        if (this.action == 'sit')
          this.action = 'stand';
        else 
          this.action = 'sit';
        this.update(this.action,this.animation);
      }
    }
    // calculate fringe hook
    this.fringeHook = Math.floor((this.y-8) / 32); 
  }

  // when other players new position is received from server, do not move them now, only slowly update their position with each frame until they are where they are supposed to be
  this.updateFuturePosition = function() {
    // are we there yet?
    if ( (this.x == this.fx)&&(this.y == this.fy) ) 
      return true;
    // if distance is bigger than 10 fields, move instantly to prevent huge lags
    if ( (Math.abs(this.x - this.fx) > 32*10) || (Math.abs(this.y - this.fy) > 32*10) ) {
      this.x = this.fx;
      this.y = this.fy;
      return;
    } 
    // find desired direction
    var dx = 0;
    var dy = 0;
    if (this.x < this.fx) { dx = +8; this.update('walk','right'); }
    if (this.x > this.fx) { dx = -8; this.update('walk','left'); }
    if (this.y < this.fy) { dy = +8; this.update('walk','down'); }
    if (this.y > this.fy) { dy = -8; this.update('walk','up'); }
    // update position
    this.x += dx;
    this.y += dy;
    // if we are close enough, stop the movement
    if (Math.abs(this.x - this.fx) <= 8) this.x = this.fx;
    if (Math.abs(this.y - this.fy) <= 8) this.y = this.fy;
  }

  // update action+animation
  this.update = function(AAction,AAnimation) {
    if (AAction=='')
      throw "Undefined action";
    if (AAnimation=='')
      throw "Undefined animation";
    this.action = AAction;
    this.animation = AAnimation;
    // bodyparts
    if (this.body) this.body.update(AAction,AAnimation); 
    if (this.hairstyle) this.hairstyle.update(AAction,AAnimation);
    if (this.leg) this.leg.update(AAction,AAnimation);
    if (this.chest) this.chest.update(AAction,AAnimation);
    if (this.feet) this.feet.update(AAction,AAnimation);
    if (this.hands) this.hands.update(AAction,AAnimation);
    if (this.head) this.head.update(AAction,AAnimation); 
  }
  this.update('stand','down');
 
  // drawing function
  this.draw = function(ALeft,ATop) {
    if (this.body) this.body.draw(ALeft,ATop);
    if (this.feet) this.feet.draw(ALeft,ATop);
    if (this.leg) this.leg.draw(ALeft,ATop);
    if (this.chest) this.chest.draw(ALeft,ATop);
    if (this.hands) this.hands.draw(ALeft,ATop);
    if (this.hairstyle) this.hairstyle.draw(ALeft,ATop);
    if (this.head) this.head.draw(ALeft+1*document.getElementById('edtWeirdX1').value,ATop+1*document.getElementById('edtWeirdY1').value);
    // chat message above header
    //var t = Math.floor(new Date().getTime()/1000);   ... cannot use local time because it may be different than server time, it would not work
    //if (t - this.chat_time <= 5) {
    //if (this.user == 6) {
      //debugClear();
      //debug('T:s='+server_time+' c='+this.chat_time);
    //}
    if (server_time - this.chat_time <= 5) {
      context.font = "12pt courier";
      context.fillStyle = "rgba(255,255,0,1.0)";
      context.textAlign = "center";
      context.fillText(this.chat,ALeft+32,ATop-10);
    }
  }
  
}

function Avatars() {
  var that = new Array();
  
  that.movement = function(AKeyMap) {
    // movement of all avatars
    for (var i=0; i<this.length; i++) {
      if (i==0)
        this[i].movement(AKeyMap);
      else {
        this[i].updateFuturePosition();
        this[i].movement();
      }
    }    
  }

  // find avatar by user
  that.byUser = function(AUser) {
    for (var i=0; i<this.length; i++)
      if (this[i].user == AUser)
        return this[i];
    return null;
  }
  
  return that;
}
